#include<iostream>
#include<functional>
#include<errno.h>
#include<string.h>
#include"Socket.hpp"
#include"EventLoop_Timequeue.hpp"


uint64_t timetask_id = rand()%10000;//定时任务的id
//通信套接字的回调函数
void CloseCallback(Channel* channel)
{
    channel->GetLoop()->RemoveEvent(channel);//移除事件监控
    int fd = channel->Fd();
    close(fd);
    LOG_INF("close fd : %d",fd);
    delete channel;
}
void ReadCallback(Channel* channel)
{
    char buf[1024];
    int n = recv(channel->Fd(),buf,sizeof(buf)-1,0);//阻塞式读取
    if(n <= 0){
        LOG_ERR("read error:%s",strerror(errno));
        CloseCallback(channel);//关闭通信套接字
        return;
    }
    buf[n] = '\0';
    channel->GetLoop()->DelayTimeTask(timetask_id);
    channel->EnableWriting();//启动可写事件
    channel->GetLoop()->ModifyEvent(channel);//修改事件
    // std::cout << "server recv:" << buf << " from " << channel->Fd() << std::endl;
    LOG_INF("server recv:%s from %d",buf,channel->Fd());
}
void WriteCallback(Channel* channel)
{
    int fd = channel->Fd();
    const char *data = "server : hello world";
    int n = send(fd,data,strlen(data),0);
    if(n < 0){
        LOG_ERR("write error:%s",strerror(errno));
        CloseCallback(channel);
        return;
    }
    channel->DisableWriting();//关闭写监控
    // channel->GetLoop()->DelayTimeTask(,1.0,std::bind(WriteCallback,channel));//延时1秒后再次触发写事件
    channel->GetLoop()->ModifyEvent(channel);//修改事件
}

void ErrorCallback(Channel* channel)
{
    CloseCallback(channel);
}

//服务器监听套接字的回调函数（底层就是accept系统调用）
void Acceptor(EventLoop *loop,Channel *socket_listen_channel)
{
    int fd = socket_listen_channel->Fd();
    int newfd = accept(fd,nullptr,nullptr);
    if(newfd < 0){
        LOG_ERR("accept error:%s",strerror(errno));
        return;
    }
    LOG_INF("new connection fd:%d",newfd);
    Channel *channel = new Channel(loop,newfd);
    //为通信套接字设置回调函数
    channel->SetReadCallback(std::bind(ReadCallback,channel));
    channel->SetWriteCallback(std::bind(WriteCallback,channel));
    channel->SetCloseCallback(std::bind(CloseCallback,channel));
    channel->SetErrorCallback(std::bind(ErrorCallback,channel));
    loop->AddEvent(channel);//将通信套接字添加进事件循环

    //添加定时任务(这个定时任务用来关闭通信套接字，即长时间没有数据交互，则关闭)，添加到EventLoop的Timequeue中
    channel->GetLoop()->AddTimeTask(timetask_id,5,std::bind(CloseCallback,channel));//5秒后没用数据交互则关闭通信套接字

    channel->EnableReading();//设置监听事件为可读(读事件，需要监听，但是写事件只有在读事件后才会触发，不能与读事件同时设置\
    原因是避免写事件一直触发，影响效率)
    channel->GetLoop()->ModifyEvent(channel);//修改事件

    
}

int main()
{
    srand(time(nullptr));//设置随机数种子
    TcpSocket ser;
    ser.Build_Server_Socket(8888,"127.0.0.1");//设置监听端口和IP地址    
    EventLoop loop;//创建事件循环(epoll监听)
    Channel socket_listen_channel(&loop,ser.Fd());//监听套接字构建Channel
    socket_listen_channel.SetReadCallback(std::bind(Acceptor,&loop,&socket_listen_channel));//设置监听套接字的回调函数为Acceptor
    loop.AddEvent(&socket_listen_channel);//将监听套接字添加进事件循环
    /*
    注意，这里需要先add监听套接字，然后再修改监听套接字的监控事件为读事件，最后一定要modify;
    这里的socket_listen_channel默认构造里默认的监控事件_event为0，所以这里需要先add监听套接字，然后再修改监听套接字的监控事件为读事件，最后一定要modify;
    如果不先add监听套接字，则后面的modify会失败，因为监听套接字还没有加入到epoll中(modify会判断是否在epoll中，不在则不执行);
    */

    socket_listen_channel.EnableReading();//将监听套接字设置为可读事件设置进epoll监听
    socket_listen_channel.GetLoop()->ModifyEvent(&socket_listen_channel);//修改监听套接字的事件
    while(true){
        loop.Start();//启动事件循环
    }

    return 0;
}


